﻿package net.wangit.view.unit;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.wangit.Element;
import net.wangit.MapList;
import net.wangit.Page;
import net.wangit.Row;
import net.wangit.Unit;
import net.wangit.context.ActionContext;
import net.wangit.framework.debug.Recorder;
import net.wangit.framework.expression.LabelExpression;
import net.wangit.framework.util.InterceptorLoader;
import net.wangit.support.UnitInterceptor;
import net.wangit.util.Checker;
import net.wangit.util.StringUtil;
import net.wangit.view.element.ElementComponent;
import net.wangit.view.element.component.UnitElement;
import net.wangit.view.page.PageImpl;
import net.wangit.view.unit.grid.Group;
import net.wangit.view.unit.grid.Wheel;
import net.wangit.view.unit.util.UnitUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public abstract class UnitComponent implements Unit, Cloneable {

	private static Log log = LogFactory.getLog(UnitComponent.class);
	protected String unitId;
	protected String groupId;
	protected String domain;
	protected String showMode;
	protected String template;
	protected int column;
	protected String tableAttribute;
	protected boolean switchable;
	protected String title;
	protected String titleCss;
	protected String toolbarCss;
	protected boolean showTitle;
	protected Map rowsCss;
	protected boolean showUnitBorder;
	protected boolean showTitleBorder;
	protected boolean showGridBorder;
	protected boolean showCellBorder;
	protected String colsConfig[][];
	protected Wheel rowsConfig;
	protected boolean rowsConfigEnabled;
	protected int width;
	protected int widthMode;
	protected int height;
	protected int heightMode;
	protected boolean showListIndex;
	protected int listSelectMode;
	protected int listSize;
	protected String navigator;
	protected boolean showListHead;
	protected boolean clickMark;
	protected boolean moveMark;
	private List elements;
	protected MapList data;
	private String content;
	protected Map attributes;
	private Page page;
	private UnitElement parent;
	private boolean isRowsVisible;
	private String name;
	protected String rowCombine;
	protected String sumConfig;
	private boolean scanable;
	private boolean addable;
	private boolean editable;
	protected int layoutMode;
	protected String groupsConfig;
	private boolean appendInsertScript;
	private boolean remember;
	private boolean recovery;
	private List interceptorList;
	private String tableName;
	private int dataMode;
	private String datasource;
	private String dataExpression;
	private String listUnitId;
	private boolean published;
	protected String queryUnitId;
	private Iterator interceptors;
	private String lastInterceptorName;
	private boolean hasAccessPrivileges;
	private boolean hasDataPrivilege;
	private boolean hasElementAccessPrivileges;
	private Set<String> elementHeadJsPaths;
	private Set<String> elementTailJsPaths;
	private Set<String> elementCssPaths;

	public UnitComponent() {
		showMode = "s";
		switchable = false;
		showTitle = true;
		rowsCss = new HashMap();
		rowsConfigEnabled = true;
		width = -1;
		widthMode = 0;
		height = -1;
		heightMode = 0;
		elements = new ArrayList();
		attributes = new HashMap();
		isRowsVisible = true;
		recovery = true;
		hasAccessPrivileges = false;
		hasDataPrivilege = false;
		hasElementAccessPrivileges = false;
		elementHeadJsPaths = new HashSet<String>();
		elementTailJsPaths = new HashSet<String>();
		elementCssPaths = new HashSet<String>();
	}

	protected abstract void configure(Row row);

	public String write(ActionContext ac) throws Exception {
		if (interceptors != null && interceptors.hasNext()) {
			UnitInterceptor interceptor = (UnitInterceptor) interceptors.next();
			if (Recorder.isEnabled()) {
				if (lastInterceptorName != null)
					Recorder.record((new StringBuilder("UI: "))
							.append(lastInterceptorName).append(" (")
							.append(unitId).append(")").toString());
				lastInterceptorName = interceptor.getClass().getName();
			}
			return interceptor.intercept(ac, this);
		}
		if (Recorder.isEnabled() && lastInterceptorName != null)
			Recorder.record((new StringBuilder("UI: "))
					.append(lastInterceptorName).append(" (").append(unitId)
					.append(")").toString());
		return writeUnit(ac);
	}

	protected void cloneAfter(ActionContext ac) {
		interceptors = InterceptorLoader.getUnitInterceptors(domain,
				interceptorList);
	}

	public UnitComponent cloneUnit(ActionContext ac, Page page) {
		if (page != null) {
			PageImpl pi = (PageImpl) page;
			pi.putElementHeadJsPath(elementHeadJsPaths);
			pi.putElementTailJsPath(elementTailJsPaths);
			pi.putElementCssPath(elementCssPaths);
		}
		UnitComponent newUnit;
		try {
			newUnit = (UnitComponent) super.clone();
			newUnit.setPage(page);
			List newElements = new ArrayList();
			for (int i = 0; i < newUnit.size(); i++) {
				ElementComponent e = (ElementComponent) newUnit.getElement(i);
				ElementComponent ec = e.cloneElement(ac, page);
				ec.setParent(newUnit);
				newElements.add(ec);
			}

			newUnit.setElements(newElements);
			newUnit.cloneAfter(ac);
			return newUnit;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	protected String writeUnit(ActionContext ac) {
		StringBuffer html;
		html = new StringBuffer("<input type=\"hidden\" name=\"");
		html.append("_u_").append("\" value=\"").append(UnitUtil.getKey(this))
				.append("\"/>\n");
		if (isRemember()) {
			// 启用记忆，在表单提交后数据会存入会话（Session），下一次进入此页面时数据自动还原。
			html.append("<input type=\"hidden\" name=\"").append("_ru_")
					.append("\" value=\"").append(UnitUtil.getKey(this))
					.append("\"/>\n");
		}
		html.append(getWriter().writeUnit(ac, this));
		clear();
		if (Recorder.isEnabled())
			Recorder.record((new StringBuilder("write unit: ")).append(unitId)
					.toString());
		return html.toString();
	}

	public abstract UnitWriter getWriter();

	public abstract void addElement2Group(ActionContext actioncontext,
			Group group, ElementComponent elementcomponent);

	public void setId(String id) {
		unitId = id;
	}

	public String getId() {
		return unitId;
	}

	public void setColsConfig(String colsConfig) {
		if (!Checker.isEmpty(colsConfig))
			this.colsConfig = StringUtil.split(colsConfig, ";", ",");
	}

	public void setColumn(int column) {
		this.column = column;
	}

	public MapList getData() {
		return data;
	}

	public void setData(MapList data) {
		this.data = data;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public void setHeightMode(int heightMode) {
		this.heightMode = heightMode;
	}

	public void setListSelectMode(int listSelectMode) {
		this.listSelectMode = listSelectMode;
	}

	public void setListSize(int listSize) {
		this.listSize = listSize;
	}

	public void setRowsConfig(String rowsConfig) {
		if (!Checker.isEmpty(rowsConfig))
			this.rowsConfig = new Wheel(StringUtil.split(rowsConfig, ","));
	}

	public void setShowListHead(boolean showListHead) {
		this.showListHead = showListHead;
	}

	public void setTableAttribute(String tableAttribute) {
		this.tableAttribute = tableAttribute;
	}

	public void setTemplate(String template) {
		this.template = template;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public void setWidthMode(int widthMode) {
		this.widthMode = widthMode;
	}

	public int size() {
		return elements.size();
	}

	public Element getElement(String elementId) {
		return getElementComponent(elementId);
	}

	public Element getElement(int index) {
		return (Element) elements.get(index);
	}

	public ElementComponent getElementComponent(String elementId) {
		if (!Checker.isEmpty(elementId)) {
			for (int i = 0; i < elements.size(); i++) {
				ElementComponent ec = (ElementComponent) elements.get(i);
				if (elementId.equals(ec.getId()))
					return ec;
			}

		}
		return null;
	}

	public ElementComponent getElementComponent(int index) {
		return (ElementComponent) elements.get(index);
	}

	public void removeElement(int index) {
		elements.remove(index);
	}

	public void removeElement(String elementId) {
		if (!Checker.isEmpty(elementId)) {
			for (int i = 0; i < elements.size(); i++) {
				ElementComponent ec = (ElementComponent) elements.get(i);
				if (!elementId.equals(ec.getId()))
					continue;
				elements.remove(i);
				break;
			}

		}
	}

	public void removeGroup(String groupId) {
		if (!Checker.isEmpty(groupId) && !Checker.isEmpty(groupsConfig)) {
			for (int i = 0; i < elements.size(); i++) {
				ElementComponent ec = (ElementComponent) elements.get(i);
				if (groupId.equals(ec.getGroupId())) {
					elements.remove(i);
					i--;
				}
			}

			StringBuffer newGroupsConfig = new StringBuffer();
			String configs[][] = StringUtil.split(groupsConfig, ";", ",");
			for (int i = 0; i < configs.length; i++)
				if (!groupId.equals(configs[i][0])) {
					for (int j = 0; j < configs[i].length; j++)
						newGroupsConfig.append(configs[i][j]).append(",");

					newGroupsConfig.append(";");
				}

			groupsConfig = newGroupsConfig.toString();
		}
	}

	public void addElement(Element element) {
		try {
			ElementComponent ec = (ElementComponent) element;
			ec.setParent(this);
			elements.add(ec);
		} catch (Exception e) {
			throw new UnsupportedOperationException(
					"ElementComponent is expected!");
		}
	}

	public void addElement(int index, Element element) {
		try {
			ElementComponent ec = (ElementComponent) element;
			ec.setParent(this);
			elements.add(index, ec);
		} catch (Exception e) {
			throw new UnsupportedOperationException(
					"ElementComponent is expected!");
		}
	}

	public void setShowListIndex(boolean showListIndex) {
		this.showListIndex = showListIndex;
	}

	public void setShowGridBorder(boolean showGridBorder) {
		this.showGridBorder = showGridBorder;
	}

	public void setShowMode(String showMode) {
		this.showMode = showMode;
	}

	public Map<String, String> getAttributes() {
		return attributes;
	}

	public void setClickMark(boolean clickMark) {
		this.clickMark = clickMark;
	}

	public void setMoveMark(boolean moveMark) {
		this.moveMark = moveMark;
	}

	public void setShowTitleBorder(boolean showTitleBorder) {
		this.showTitleBorder = showTitleBorder;
	}

	public void setShowCellBorder(boolean showCellBorder) {
		this.showCellBorder = showCellBorder;
	}

	public void setShowUnitBorder(boolean showUnitBorder) {
		this.showUnitBorder = showUnitBorder;
	}

	public void setShowTitle(boolean showTitle) {
		this.showTitle = showTitle;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getTitleCss() {
		return Checker.isEmpty(titleCss) ? "UT" : titleCss;
	}

	public void setTitleCss(String titleCss) {
		this.titleCss = titleCss;
	}

	public String getToolbarCss() {
		return Checker.isEmpty(toolbarCss) ? "UBAR" : toolbarCss;
	}

	public void setToolbarCss(String toolbarCss) {
		this.toolbarCss = toolbarCss;
	}

	public String getNavigator() {
		return navigator;
	}

	public String getDomain() {
		return domain;
	}

	public String getShowMode() {
		return showMode;
	}

	public String getGroupId() {
		return groupId;
	}

	public void setRowCss(int rowIndex, String rowCss) {
		rowsCss.put(new Integer(rowIndex), rowCss);
	}

	public int getColumn() {
		return column;
	}

	public boolean isShowTitle() {
		return showTitle;
	}

	public boolean isShowUnitBorder() {
		return showUnitBorder;
	}

	public boolean isShowGridBorder() {
		return showGridBorder;
	}

	public boolean isShowTitleBorder() {
		return showTitleBorder;
	}

	public boolean isShowCellBorder() {
		return showCellBorder;
	}

	public int getWidth() {
		return width;
	}

	public int getWidthMode() {
		return widthMode;
	}

	public int getHeight() {
		return height;
	}

	public int getHeightMode() {
		return heightMode;
	}

	public String[][] getColsConfig() {
		return colsConfig;
	}

	public int getLayoutMode() {
		return layoutMode;
	}

	public void setLayoutMode(int layoutMode) {
		this.layoutMode = layoutMode;
	}

	public String[][] getGroupsConfig(ActionContext ac) {
		if (!Checker.isEmpty(groupsConfig))
			return StringUtil.split(LabelExpression.resolve(ac, groupsConfig),
					";", ",");
		else
			return null;
	}

	public void setGroupsConfig(String groupsConfig) {
		this.groupsConfig = groupsConfig;
	}

	public int getListSelectMode() {
		return listSelectMode;
	}

	public int getListSize() {
		return listSize;
	}

	public boolean isShowListHead() {
		return showListHead;
	}

	public String getTableAttribute() {
		return tableAttribute;
	}

	public boolean isShowListIndex() {
		return showListIndex;
	}

	public String getTemplate() {
		return template;
	}

	public void setElements(List bodyElements) {
		elements = bodyElements;
	}

	public void clear() {
		attributes.clear();
		attributes = new HashMap();
	}

	protected void setInterceptors(String interceptors) {
		try {
			interceptorList = InterceptorLoader
					.loadUnitInterceptors(interceptors);
		} catch (Exception e) {
			log.error((new StringBuilder("could not load unit interceptors: "))
					.append(interceptors).toString(), e);
			throw new UnitConfigurationException((new StringBuilder(
					"could not load unit interceptors: ")).append(interceptors)
					.toString(), domain, unitId, "unit interceptors", e);
		}
	}

	public String getOperator() {
		String showMode = getShowMode();
		if ("a".equals(showMode))
			return "1";
		if ("e".equals(showMode))
			return "2";
		if ("s".equals(showMode))
			return "0";
		else
			return "";
	}

	protected void setDomain(String domain) {
		this.domain = domain;
	}

	public String getTableName() {
		return tableName;
	}

	protected void setTableName(String tableName) {
		this.tableName = tableName;
	}

	public String getDatasource() {
		return datasource;
	}

	protected void setDatasource(String datasource) {
		this.datasource = datasource;
	}

	public boolean isAddable() {
		return addable;
	}

	protected void setAddable(boolean addable) {
		this.addable = addable;
	}

	public boolean isEditable() {
		return editable;
	}

	protected void setEditable(boolean editable) {
		this.editable = editable;
	}

	protected void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public boolean isRemember() {
		return remember;
	}

	protected void setRemember(boolean remember) {
		this.remember = remember;
	}

	public boolean isRecovery() {
		return recovery;
	}

	protected void setRecovery(boolean recovery) {
		this.recovery = recovery;
	}

	public boolean isScanable() {
		return scanable;
	}

	protected void setScanable(boolean scanable) {
		this.scanable = scanable;
	}

	public String getQueryUnitId() {
		return queryUnitId;
	}

	public String getListUnitId() {
		return listUnitId;
	}

	protected void setQueryUnitId(String queryUnitId) {
		this.queryUnitId = queryUnitId;
	}

	protected void setListUnitId(String listUnitId) {
		this.listUnitId = listUnitId;
	}

	public boolean isAppendInsertScript() {
		return appendInsertScript;
	}

	public void setAppendInsertScript(boolean appendInsertScript) {
		this.appendInsertScript = appendInsertScript;
	}

	public final boolean hasElementAccessPrivileges() {
		return hasElementAccessPrivileges;
	}

	protected final void setHasElementAccessPrivileges(
			boolean hasElementAccessPrivileges) {
		this.hasElementAccessPrivileges = this.hasElementAccessPrivileges
				|| hasElementAccessPrivileges;
	}

	public boolean hasAccessPrivileges() {
		return hasAccessPrivileges;
	}

	protected void setHasAccessPrivileges(boolean hasAccessPrivileges) {
		this.hasAccessPrivileges = hasAccessPrivileges;
	}

	public boolean hasDataPrivilege() {
		return hasDataPrivilege;
	}

	protected void setHasDataPrivilege(boolean hasDataPrivilege) {
		this.hasDataPrivilege = hasDataPrivilege;
	}

	public UnitElement getParent() {
		return parent;
	}

	public void setParent(UnitElement parent) {
		this.parent = parent;
	}

	public String getName() {
		return name;
	}

	protected void setName(String name) {
		this.name = name;
	}

	public String getDataExpression() {
		return dataExpression;
	}

	protected void setDataExpression(String dataExpression) {
		if (Checker.isEmpty(dataExpression)) {
			this.dataExpression = dataExpression;
		} else {
			dataExpression = dataExpression.replaceAll("\r\n", " ");
			dataExpression = dataExpression.replaceAll("\r", " ");
			this.dataExpression = dataExpression.replaceAll("\n", " ");
		}
	}

	public int getDataMode() {
		return dataMode;
	}

	protected void setDataMode(int dataMode) {
		this.dataMode = dataMode;
	}

	public String getRowCss(int i) {
		String css = (String) rowsCss.get(new Integer(i));
		if (css != null)
			return css;
		if (rowsConfigEnabled && rowsConfig != null)
			return rowsConfig.get(1);
		if (isShowCellBorder())
			return "RB";
		else
			return null;
	}

	public boolean isRowsConfigEnabled() {
		return rowsConfigEnabled;
	}

	public void setRowsConfigEnabled(boolean rowsConfigEnabled) {
		this.rowsConfigEnabled = rowsConfigEnabled;
	}

	protected void setRowsCss(Map rowsCss) {
		this.rowsCss = rowsCss;
	}

	public String getRowCombine() {
		return rowCombine;
	}

	public void setRowCombine(String rowCombine) {
		this.rowCombine = rowCombine;
	}

	public String getSumConfig() {
		return sumConfig;
	}

	public boolean isClickMark() {
		return clickMark;
	}

	public boolean isMoveMark() {
		return moveMark;
	}

	public boolean isRowsVisible() {
		return isRowsVisible;
	}

	public void setRowsVisible(boolean isRowsVisible) {
		this.isRowsVisible = isRowsVisible;
	}

	public boolean isPublished() {
		return published;
	}

	protected void setPublished(boolean published) {
		this.published = published;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public void setSumConfig(String sumConfig) {
		this.sumConfig = sumConfig;
	}

	public boolean isSwitchable() {
		return switchable;
	}

	public void setSwitchable(boolean switchable) {
		this.switchable = switchable;
	}

	public Page getPage() {
		return page;
	}

	protected void setPage(Page page) {
		this.page = page;
	}

	protected void putElementHeadJsPath(String jsPath) {
		elementHeadJsPaths.add(jsPath);
	}

	protected void putElementTailJsPath(String jsPath) {
		elementTailJsPaths.add(jsPath);
	}

	protected void putElementCssPath(String cssPath) {
		elementCssPaths.add(cssPath);
	}

}
